#include <iostream>
#include "InputSourceManager.h"
#include "Protocol/ProtocolApi.h"

using namespace Protocol;

InputSourceManager::Ptr InputSourceManager::instance(){
    static auto ptr = std::make_shared<InputSourceManager>();
    return ptr;
}

InputSourceManager::InputSourceManager(const std::string& sourceDbName){
    m_db_path = sourceDbName;
    RegistRPC();

    try{
        m_storager_ptr = std::make_shared<internal::storage_t<StorageType>>(m_db_path, 
            make_table("input_source",
                            make_column("id", &InputSource::m_id, primary_key()),
                            make_column("type", &InputSource::m_source_type),
                            make_column("ability", &InputSource::m_source_ability),
                            make_column("content", &InputSource::m_source_content),
                            make_column("desc", &InputSource::m_source_desc)));
        m_storager_ptr->sync_schema();
    }catch(const std::system_error& e){
        std::cout << e.what() << std::endl;
        m_storager_ptr.reset();
    }
    
}

InputSourceManager::~InputSourceManager(){

}


void InputSourceManager::RegistRPC(){
    RPCMethodMap method_map;

    method_map.emplace("Add", CRPCFuntion::CreateRpc([this](const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
		return Add(request, inMap, response, outMap);
	}));

    method_map.emplace("Delete", CRPCFuntion::CreateRpc([this](const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
		return Delete(request, inMap, response, outMap);
	}));

    method_map.emplace("Set", CRPCFuntion::CreateRpc([this](const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
		return Set(request, inMap, response, outMap);
	}));

    method_map.emplace("Get", CRPCFuntion::CreateRpc([this](const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
		return Get(request, inMap, response, outMap);
	}));
	
	IProtocolInterface::GetInstance()->RegistProtocol("InputSource", method_map);
}

bool InputSourceManager::Add(const Json::Value &request, 
    const Fdt::BufferMap::Ptr &inMap, Json::Value &response, Fdt::BufferMap::Ptr &outMap){

    std::string type;
	if(!Json::getJsonString(request, "Param.Type", type)){
		response["data"]["Param"]["Result"] = false;
		return false;
	}

    if(type != "NETWORK"){
        response["data"]["Param"]["Result"] = false;
		return false;
    }

    std::string ability;
    if(!Json::getJsonString(request, "Param.Ability", ability)){
		response["data"]["Param"]["Result"] = false;
		return false;
	}

    if(ability != "video_audio" && ability != "audio" && ability != "video"){
        response["data"]["Param"]["Result"] = false;
		return false;
    }

    std::string content;
    if(!Json::getJsonString(request, "Param.Content", content)){
		response["data"]["Param"]["Result"] = false;
		return false;
	}

    std::string desc;
    Json::getJsonString(request, "Param.Desc", desc);

    if(!m_storager_ptr) return false;

    InputSource source_entry;
    source_entry.m_source_ability = ability;
    source_entry.m_source_type = type;
    source_entry.m_source_content = content;
    source_entry.m_source_desc = desc;

    try{
        source_entry.m_id = m_storager_ptr->insert(source_entry);
        response["data"]["Param"]["SourceId"] = source_entry.m_id;
    }catch(const std::system_error& e){
        std::cout << e.what() << std::endl;
        response["data"]["Param"]["Result"] = false;
		return false;
    }

    return true;
}
bool InputSourceManager::Delete(const Json::Value &request, const Fdt::BufferMap::Ptr &inMap, 
    Json::Value &response, Fdt::BufferMap::Ptr &outMap){
    int sourceId = -1;
	if(!Json::getJsonInt(request, "Param.SourceId", sourceId)){
		response["data"]["Param"]["Result"] = false;
		return false;
	}

    try{
        m_storager_ptr->remove<InputSource>(sourceId);
        response["data"]["Param"]["SourceId"] = sourceId;
    }catch(const std::system_error& e){
        std::cout << e.what() << std::endl;
        response["data"]["Param"]["Result"] = false;
		return false;
    }
    
    return true;
}
bool InputSourceManager::Set(const Json::Value &request, const Fdt::BufferMap::Ptr &inMap, 
    Json::Value &response, Fdt::BufferMap::Ptr &outMap){
    
    int sourceId = -1;
	if(!Json::getJsonInt(request, "Param.SourceId", sourceId)){
		response["data"]["Param"]["Result"] = false;
		return false;
	}

    std::string type;
	if(!Json::getJsonString(request, "Param.Type", type)){
		response["data"]["Param"]["Result"] = false;
		return false;
	}

    if(type != "NETWORK"){
        response["data"]["Param"]["Result"] = false;
		return false;
    }

    std::string ability;
    if(!Json::getJsonString(request, "Param.Ability", ability)){
		response["data"]["Param"]["Result"] = false;
		return false;
	}

    if(ability != "video_audio" && ability != "audio" && ability != "video"){
        response["data"]["Param"]["Result"] = false;
		return false;
    }

    std::string content;
    if(!Json::getJsonString(request, "Param.Content", content)){
		response["data"]["Param"]["Result"] = false;
		return false;
	}

    std::string desc;
    Json::getJsonString(request, "Param.Desc", desc);

    if(!m_storager_ptr) return false;

    InputSource source_entry;
    source_entry.m_source_ability = ability;
    source_entry.m_source_type = type;
    source_entry.m_source_content = content;
    source_entry.m_id = sourceId;
    source_entry.m_source_desc = desc;

    try{
        m_storager_ptr->replace(source_entry);
    }catch(const std::system_error& e){
        std::cout << e.what() << std::endl;
        m_storager_ptr.reset();
    }

    return true;
}
bool InputSourceManager::Get(const Json::Value &request, const Fdt::BufferMap::Ptr &inMap, 
    Json::Value &response, Fdt::BufferMap::Ptr &outMap){
    int sourceId = -1;
    Json::getJsonInt(request, "Param.SourceId", sourceId);
    Json::Value sourceList;

	if(sourceId <= 0){  //返回所有输入源
        try{
            auto sources = m_storager_ptr->get_all<InputSource>();
            for(auto& source: sources){
                Json::Value json_source;
                json_source["Type"] = source.m_source_type;
                json_source["SourceId"] = source.m_id;
                json_source["Ability"] = source.m_source_ability;
                json_source["Content"] = source.m_source_content;
                json_source["Desc"] = source.m_source_desc;
                sourceList.append(json_source);
            }
        }catch(const std::system_error& e){
            std::cout << e.what() << std::endl;
            response["data"]["Param"]["Result"] = false;
		    return false;
        }
    }else{ //返回指定输入源
        try{
            auto sources = m_storager_ptr->get_all<InputSource>(where(is_equal(&InputSource::m_id, sourceId)));
            for(auto& source: sources){
                Json::Value json_source;
                json_source["Type"] = source.m_source_type;
                json_source["SourceId"] = source.m_id;
                json_source["Ability"] = source.m_source_ability;
                json_source["Content"] = source.m_source_content;
                json_source["Desc"] = source.m_source_desc;
                sourceList.append(json_source);
                break;
            }
        }catch(const std::system_error& e){
            std::cout << e.what() << std::endl;
            response["data"]["Param"]["Result"] = false;
		    return false;
        }
    }
    
    Json::Value hdmi_source;
    hdmi_source["Type"] = "HDMI";
    hdmi_source["SourceId"] = 10001;
    hdmi_source["Ability"] = "video";
    hdmi_source["Content"] = "substream8";
    hdmi_source["Desc"] = "hdmi input";

    sourceList.append(hdmi_source);

    response["data"]["Param"]["InputSourceList"] = sourceList;
    return true;
}